﻿#pragma once
#include <chrono>
#include <cstdint>
#include <iostream>
#include <tuple>

#include "MyPrtFns.h"

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 平台兼容性宏

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx platform
#define MY_PLTFM_UNKNOWN (static_assert(false, "unkown platform"));

// 处理不同平台和编译器的差异
#if defined(_WIN32) || defined(_WIN64)
#define MY_PLTFM_WIN 1
#elif defined(__linux__)
#define MY_PLTFM_LINUX 1
#endif

#if defined(__clang__)
#define MY_CMPLER_LLVM 10
#else
#define MY_CMPLER_LLVM 0
#endif

#if defined(_MSVC_LANG) && !defined(__clang__) /* && defined(_WIN32) && defined(_MSC_VER) */
#define MY_CMPLER_MSVC 10
#else
#define MY_CMPLER_MSVC 0
#endif

#if defined(__GNUC__) /* || defined(__GNUG__)*/
#define MY_CMPLER_GCC 10
#else
#define MY_CMPLER_GCC 0
#endif

#if defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__)
#define MY_CMPLER_MACGCC 1
#else
#define MY_CMPLER_MACGCC 0
#endif

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx function cross platform
#if MY_CMPLER_MSVC || MY_CMPLER_LLVM
#define MY_C_REDUCE std::reduce
#elif MY_CMPLER_GCC || MY_CMPLER_MACGCC
#define MY_C_REDUCE std::accumulate
#else
#define MY_C_REDUCE MY_PLTFM_UNKNOWN
#endif

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 如果在 msvc cl 环境, 使用特定的宏
#ifndef _MSVC_LANG
#define __FUNCDNAME__ __PRETTY_FUNCTION__
#define __FUNCSIG__ __PRETTY_FUNCTION__
#endif

///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 函数签名 header
/// .h 中使用
#define MY_FIN_I8 inline int8_t
#define MY_FIN_I32 inline int32_t
#define MY_FIN_VOID inline void
/// .cpp, .cxx .cu 源文件中使用
#define MY_FN_I8 int8_t
#define MY_FN_I32 int32_t
#define MY_FN_VOID void

///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 数学函数
#ifndef IMAX
#define IMAX(a, b) (((a) > (b)) ? (a) : (b))
#endif

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 测试用
//#define MYTEST(x) x // identity
#define MYPASS(x) ;  // 空语句

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx machine endian 大端序, 小端序
/* 深入理解计算机系统 2.2.5
* data.n = 0xAB'CD'EF'01;
* 01 EF CD AB 小端序
* AB CD EF 01 大端序
*/
#define MY_PRT_LIT_OR_BIG_ENDIAN                         \
    ::std::ignore = []()                                 \
    {                                                    \
        union                                            \
        {                                                \
            unsigned n;                                  \
            char ch;                                     \
        } data;                                          \
        data.n = 0xAB'CD'EF'01;                          \
        if (data.ch == 0x01)                             \
        {                                                \
            MyfPrt("This machine is [Little-endian]\n"); \
        }                                                \
        else                                             \
        {                                                \
            MyfPrt("This machine is [Big-endian]\n");    \
        }                                                \
        return 0;                                        \
    }();

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx cout, cin 加速
// https://www.zhihu.com/question/614285401/answer/3476754940
/*
* ios_base::sync_with_stdio(false)
* 这一行代码关闭了C++标准输入输出流与C标准库输入输出流的同步。
* 默认情况下，C++的输入输出流与C标准库的输入输出流是同步的，
* 这意味着每当使用C++的输入输出流时，都会同步刷新C标准库的缓冲区。
* 通过关闭同步，可以避免这种同步操作，从而提高输入输出的效率；
*
* cin.tie(nullptr):
* 这一行代码将C++标准输入流(cin)和C++标准输出流(cout)的绑定解除。
* 默认情况下，cin和cout是绑定在一起的，即在执行输入操作时，输出缓冲区会自动刷新。
* 通过解除绑定，可以避免这种自动刷新，提高输入操作的效率。
*/

#define MY_SPPEDUP_IOSTREM_CIN_COUT              \
    ::std::ignore = []()                         \
    {                                            \
        ::std::ios_base::sync_with_stdio(false); \
        ::std::cin.tie(nullptr);                 \
        return 0;                                \
    }();

//------------------------ Get Set Macro
#define SetMacro(name, type)         \
    inline void Set##name(type arg1) \
    {                                \
        if (this->name != arg1)      \
        {                            \
            this->name = arg1;       \
        }                            \
    }

#define SetMacroDirect(name, type) \
    inline void Set##name(type arg1) { this->name = arg1; }

#define GetMacro(name, type) \
    inline type Get##name() const { return this->name; }

//--------- virtual version

#define VirtualSetMacro(name, type)   \
    virtual void Set##name(type arg1) \
    {                                 \
        if (this->name != arg1)       \
        {                             \
            this->name = arg1;        \
        }                             \
    }

#define VirtualSetMacroOverride(name, type)    \
    virtual void Set##name(type arg1) override \
    {                                          \
        if (this->name != arg1)                \
        {                                      \
            this->name = arg1;                 \
        }                                      \
    }

#define VirtualGetMacro(name, type) \
    virtual type Get##name() const { return this->name; }

#define MYSize(x) ((ptrdiff_t)sizeof(x))
#define MYLen(a) (MYSize(a) / MYSize((a)[0]))
#define MYEnd(s) (MYLen(s) - 1)

///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 简单计算运行时间
#define MY_TIMEIT_I                                               \
    ::std::chrono::steady_clock::time_point _my_start_, _my_end_; \
    double _my_duration_count_;
#define MY_TIMEIT_A _my_start_ = ::std::chrono::steady_clock::now(); /*开始时间*/
#define MY_TIMEIT_B                                                                                                         \
    _my_end_ = ::std::chrono::steady_clock::now(); /*结束时间*/                                                             \
    _my_duration_count_ = (double)::std::chrono::duration_cast<::std::chrono::milliseconds>(_my_end_ - _my_start_).count(); \
    MyfPrt(">>>Run time: {} ms\t==\t", _my_duration_count_);                                                                \
    _my_duration_count_ /= 1000.0;                                                                                          \
    MyfPrt("{} sec\n", _my_duration_count_);

///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 调试和错误检查宏
/// 调试输出
#ifdef DEBUG
#define MY_DBG_PRT(fmt, ...) printf("[DEBUG] %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define MY_DBG_PRT(fmt, ...)
#endif